
package boggle;

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;

import javax.swing.*;


public class JBoggleBoard extends JPanel{
	private int size;
	private JBoggleButton[][] buttons;
	private ArrayList<JBoggleButton> selectedButtons;
	
	
	/**
	 * Listener class for buttons 
	 * 
	 */
	
	private class ButtonListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			JBoggleButton curr = (JBoggleButton)e.getSource();
			if (!selectedButtons.contains(curr)) {
				selectedButtons.add((JBoggleButton)e.getSource());
			}
			else { // button has already been selected, so truncate it
				int idx = selectedButtons.indexOf(curr);
				int endIdx = selectedButtons.size() - 1;
				for (int i = endIdx; i > idx; i--) 
					selectedButtons.remove(i);
			}
			updateButtonState();			
		}
		
	}
	/**
	 * Constructor 
	 * @param N, size of this JBoggleBoard
	 */
	 
	public JBoggleBoard(int N) {
		super();
		setLayout(new GridLayout(N, N, 5, 5));
		size  = N;
		buttons = new JBoggleButton[N][N];
		selectedButtons = new ArrayList<JBoggleButton>();
	}
	
	
	public JBoggleBoard() {
		this(BoggleBoard.DEFAULT_BOARD_SIZE);
	}
	
	/**
	 * Populate the buttons from BoggleBoard b
	 * @param b, the BoggleBoard to populate buttons
	 */
	public void setBoard(BoggleBoard b) {
		if (this.size != b.size()) 
			throw new IllegalArgumentException("illegal argument!");
		int N = b.size();
		for (int i = 0; i < N; i++) {
			for(int j = 0; j < N; j++) {
				String buttonStr = b.getCell(i, j);
				if (buttons[i][j] != null)
					remove(buttons[i][j]);
				buttons[i][j] = new JBoggleButton(buttonStr,i,j);
				buttons[i][j].addActionListener(new ButtonListener());
				add(buttons[i][j]);
			}
		}
	}
	
	/**
	 * clear all selected buttons
	 */
	
	public void clearSelections() {
		selectedButtons.clear();
		updateButtonState();
	}
	
	/**
	 * get the words currently selected
	 * the selection words are in seletctedButtons ArrayList
	 * @return words currently selected.
	 */
	public String getWord() {
		String res = "";
		for(JBoggleButton bt : selectedButtons) {
			res += bt.getButtonString();
		}
		return res;
	}
	
	
	/**
	 * Disable all buttons, used at game start
	 */
	public void disableAllButtons() {
		int N = size;
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++){
				buttons[i][j].setButtonState(JBoggleButton.STATE_UNAVAILABLE);
			}
		}
	}
	
	/**
	 * generate a JBoggleBoard at game start.
	 * @return a JBoggleBoard with letters BOGGLE
	 */
	
	public static JBoggleBoard generateGameStartBoard(int size) {
		BoggleBoard b = new BoggleBoard(size);
		b.setToGameStartBoard();
		JBoggleBoard res = new JBoggleBoard(size);
		res.setBoard(b);
		return res;
	}
	
	
	/**
	 *  update buttons state according to selection state
	 *  If no button is pressed (selected), set call buttons to be available.
	 *
	 */
	private void updateButtonState() {
		int N = size;
			
		if (selectedButtons.size() != 0) {
			//Iterate through all cells and set them to "unavailable."
			for (int i = 0; i < N; i++) {
				for (int j = 0; j < N; j++){
					buttons[i][j].setButtonState(JBoggleButton.STATE_UNAVAILABLE);
				}
			}
			// Iterate through the selection-list, 
			// and set each of these cells to "selected."
			for(JBoggleButton bt : selectedButtons) 
				bt.setButtonState(JBoggleButton.STATE_SELECTED);
			// Get the last button in the selection-list, and set all 
			// of its immediate neighbors to "available," unless they are already
			// in the "selected" state. (Hint: Being able to retrieve the grid-location of a button 
			// will be very useful for this step...)
			int endIdx = selectedButtons.size() - 1;
			JBoggleButton last = selectedButtons.get(endIdx);

			for (JBoggleButton bt : getNeighbourButtons(last)) {
				if (!selectedButtons.contains(bt))
					bt.setButtonState(JBoggleButton.STATE_AVAILABLE);
			}
		}
		else {
			//Iterate through all cells and set them to "available."
			for (int i = 0; i < N; i++) {
				for (int j = 0; j < N; j++){
					buttons[i][j].setButtonState(JBoggleButton.STATE_AVAILABLE);
				}
			}
		}
		
	}
	
	/**
	 * return all the buttons , which is  a neighbour of current button
	 * @param button , current considered button
	 * @return  an ArrayList of neighboring buttons.
	 */
	private ArrayList<JBoggleButton> getNeighbourButtons(JBoggleButton button) {
		ArrayList<JBoggleButton> res = new ArrayList<JBoggleButton>();
		int xcoord = button.getBoardX();
		int ycoord = button.getBoardY();
		for (int i = -1; i <= 1; i++) {
			for (int j = -1; j <= 1; j++) {
				if (i != 0 || j != 0) {
					if (inBoardBound(xcoord + i, ycoord + j))
						res.add(buttons[xcoord + i][ycoord + j]);
				}
			}
		}
		return res;
	}

	
	/**
	 * Determine if (row, col) is in board bound
	 * @param row , row index
	 * @param col , column index
	 * @return , true if in bound , false otherwise
	 */
	private boolean inBoardBound(int row, int col) {
		return row >= 0 && row < size && col >= 0 && col < size;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		 JFrame f = new JFrame("BoggleTest");
         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         f.setLayout(new FlowLayout());
         final JBoggleBoard boardGUI = new JBoggleBoard(BoggleBoard.DEFAULT_BOARD_SIZE);
         f.add(boardGUI);
         
         f.pack();
         f.setVisible(true);
         f.setSize(300, 300);
         boardGUI.setBoard(new BoggleBoard());
         
         JButton bt = new JButton("Show selected Word");
         bt.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				System.out.println("Selected word: " + boardGUI.getWord());
				
			}
        	 
         });
         f.add(bt);
	}
	
}
